package cn.edu.jlu.community.util;

import cn.edu.jlu.community.BuildConfig;

import org.apache.commons.lang3.StringUtils;

/**
 * Simple wrap class of android.util.Log
 */
public class Log {

    private static String LOG_PREFIX = "Log.";

    private final static String MSG_TR_NULL   = "\u3000";
    private final static String MSG_OBJ_NULL  = "null";
    private final static String MSG_OBJ_EMPTY = "\u3000";

    private Log() {}

    private static boolean debugMode() {
        return BuildConfig.DEBUG;
    }

    private static String getTag(StackTraceElement[] elements) {
        String tag = StringUtils.remove(elements[1].getFileName(), ".java");
        return LOG_PREFIX + StringUtils.rightPad(tag, 25, "\u00a0");
    }

    /**
     * Send a VERBOSE log message.
     *
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
    public static int v(Object obj) {
        return v(getTag(new Throwable().getStackTrace()), obj);
    }

    /**
     * Send a VERBOSE log message and log the exception.
     *
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
//    public static int v(Object obj, Throwable tr) {
//        return v(getTag(new Throwable().getStackTrace()), obj, tr);
//    }

    /**
     * Send a VERBOSE log message.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
    public static int v(String tag, Object obj) {
        return v(tag, obj, null);
    }

    /**
     * Send a VERBOSE log message and log the exception.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
    public static int v(String tag, Object obj, Throwable tr) {
        if (debugMode()) {
            String msg;
            if (obj != null) {
                msg = obj.toString();
                if (msg.trim().isEmpty()) {
                    msg = MSG_OBJ_EMPTY;
                }
            } else {
                msg = MSG_OBJ_NULL;
            }
            return android.util.Log.v(tag, msg, tr);
        }
        return 0;
    }

    /**
     * Send a DEBUG log message.
     *
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
    public static int d(Object obj) {
        return d(getTag(new Throwable().getStackTrace()), obj);
    }

    /**
     * Send a DEBUG log message and log the exception.
     *
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
//    public static int d(Object obj, Throwable tr) {
//        return d(getTag(new Throwable().getStackTrace()), obj, tr);
//    }

    /**
     * Send a DEBUG log message.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
    public static int d(String tag, Object obj) {
        return d(tag, obj, null);
    }

    /**
     * Send a DEBUG log message and log the exception.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
    public static int d(String tag, Object obj, Throwable tr) {
        if (debugMode()) {
            String msg;
            if (obj != null) {
                msg = obj.toString();
                if (msg.trim().isEmpty()) {
                    msg = MSG_OBJ_EMPTY;
                }
            } else {
                msg = MSG_OBJ_NULL;
            }
            return android.util.Log.d(tag, msg, tr);
        }
        return 0;
    }

    /**
     * Send a INFO log message.
     *
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
    public static int i(Object obj) {
        return i(getTag(new Throwable().getStackTrace()), obj);
    }

    /**
     * Send a INFO log message and log the exception.
     *
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
//    public static int i(Object obj, Throwable tr) {
//        return i(getTag(new Throwable().getStackTrace()), obj, tr);
//    }

    /**
     * Send a INFO log message.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
    public static int i(String tag, Object obj) {
        return i(tag, obj, null);
    }

    /**
     * Send a INFO log message and log the exception.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
    public static int i(String tag, Object obj, Throwable tr) {
        if (debugMode()) {
            String msg;
            if (obj != null) {
                msg = obj.toString();
                if (msg.trim().isEmpty()) {
                    msg = MSG_OBJ_EMPTY;
                }
            } else {
                msg = MSG_OBJ_NULL;
            }
            return android.util.Log.i(tag, msg, tr);
        }
        return 0;
    }

    /**
     * Send a WARN log message.
     *
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
    public static int w(Object obj) {
        return w(getTag(new Throwable().getStackTrace()), obj);
    }

    /**
     * Send a WARN log message and log the exception.
     *
     * @param tr An exception to log.
     * @return The number of bytes written.
     */
    public static int w(Throwable tr) {
        return w(getTag(new Throwable().getStackTrace()), tr);
    }

    /**
     * Send a WARN log message and log the exception.
     *
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
//    public static int w(Object obj, Throwable tr) {
//        return w(getTag(new Throwable().getStackTrace()), obj, tr);
//    }

    /**
     * Send a WARN log message.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
    public static int w(String tag, Object obj) {
        return w(tag, obj, null);
    }

    /**
     * Send a WARN log message and log the exception.
     *
     * @param tag Used to identify the source of a log message.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
    public static int w(String tag, Throwable tr) {
        if (debugMode()) {
            if (tr != null) {
                return android.util.Log.w(tag, tr);
            } else {
                return android.util.Log.w(tag, MSG_TR_NULL);
            }
        }
        return 0;
    }

    /**
     * Send a WARN log message and log the exception.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
    public static int w(String tag, Object obj, Throwable tr) {
        if (debugMode()) {
            String msg;
            if (obj != null) {
                msg = obj.toString();
                if (msg.trim().isEmpty()) {
                    msg = MSG_OBJ_EMPTY;
                }
            } else {
                msg = MSG_OBJ_NULL;
            }
            return android.util.Log.w(tag, msg, tr);
        }
        return 0;
    }

    /**
     * Send a ERROR log message.
     *
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
    public static int e(Object obj) {
        return e(getTag(new Throwable().getStackTrace()), obj, null);
    }

    /**
     * Send a ERROR log message and log the exception.
     *
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
    public static int e(Object obj, Throwable tr) {
        return e(getTag(new Throwable().getStackTrace()), obj, tr);
    }

    /**
     * Send a ERROR log message.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
//    public static int e(String tag, Object obj) {
//        return e(tag, obj, null);
//    }

    /**
     * Send a ERROR log message and log the exception.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
    public static int e(String tag, Object obj, Throwable tr) {
        if (debugMode()) {
            String msg;
            if (obj != null) {
                msg = obj.toString();
                if (msg.trim().isEmpty()) {
                    msg = MSG_OBJ_EMPTY;
                }
            } else {
                msg = MSG_OBJ_NULL;
            }
            return android.util.Log.e(tag, msg, tr);
        }
        return 0;
    }

    /**
     * What a Terrible Failure: Report a condition that should never happen.
     * The error will always be logged at level ASSERT with the call stack.
     * Depending on system configuration, a report may be added to the
     * android.os.DropBoxManager and/or the process may be terminated
     * immediately with an error dialog.
     *
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
    public static int wtf(Object obj) {
        return wtf(getTag(new Throwable().getStackTrace()), obj);
    }

    /**
     * What a Terrible Failure: Report an exception that should never happen.
     * Similar to {@link #wtf(Object)}, with an exception to log.
     *
     * @param tr An exception to log.
     * @return The number of bytes written.
     */
    public static int wtf(Throwable tr) {
        return wtf(getTag(new Throwable().getStackTrace()), tr);
    }

    /**
     * What a Terrible Failure: Report an exception that should never happen.
     * Similar to {@link #wtf(Throwable)}, with a message as well.
     *
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
//    public static int wtf(Object obj, Throwable tr) {
//        return wtf(getTag(new Throwable().getStackTrace()), obj, tr);
//    }

    /**
     * What a Terrible Failure: Report a condition that should never happen.
     * The error will always be logged at level ASSERT with the call stack.
     * Depending on system configuration, a report may be added to the
     * android.os.DropBoxManager and/or the process may be terminated
     * immediately with an error dialog.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @return The number of bytes written.
     */
    public static int wtf(String tag, Object obj) {
        return wtf(tag, obj, null);
    }

    /**
     * What a Terrible Failure: Report an exception that should never happen.
     * Similar to {@link #wtf(String, Object)}, with an exception to log.
     *
     * @param tag Used to identify the source of a log message.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
    public static int wtf(String tag, Throwable tr) {
        if (debugMode()) {
            if (tr != null) {
                return android.util.Log.wtf(tag, tr);
            } else {
                return android.util.Log.wtf(tag, MSG_TR_NULL);
            }
        }
        return 0;
    }

    /**
     * What a Terrible Failure: Report an exception that should never happen.
     * Similar to {@link #wtf(String, Throwable)}, with a message as well.
     *
     * @param tag Used to identify the source of a log message.
     * @param obj Any object you would like logged.
     * @param tr  An exception to log.
     * @return The number of bytes written.
     */
    public static int wtf(String tag, Object obj, Throwable tr) {
        if (debugMode()) {
            String msg;
            if (obj != null) {
                msg = obj.toString();
                if (msg.trim().isEmpty()) {
                    msg = MSG_OBJ_EMPTY;
                }
            } else {
                msg = MSG_OBJ_NULL;
            }
            return android.util.Log.wtf(tag, msg, tr);
        }
        return 0;
    }

    /**
     * Handy function to getContact a loggable stack trace from a Throwable
     *
     * @param tr An exception to log
     */
    public static String getStackTraceString(Throwable tr) {
        return android.util.Log.getStackTraceString(tr);
    }
}
